﻿using System;
using System.Windows.Input;
using ClientOverflow.DataTransferObjects;
using ClientOverflow.ViewModels.Interfaces;
using DynamicControllersGeneration;

namespace ClientOverflow.ViewModels.QuestionViewViewModels
{
    /// <summary>
    /// QuestionAnswerViewModel is a view-model that wraps a single answer as a model. The view-model
    /// expose the answer content and the votes summary. The view-model exposes command for voting an
    /// answer up or down.
    /// The QuestionAnswerViewModel is an abstract class which is instantiated through a factory method
    /// CreateQuestionAnswerViewModel. The class instantiated by a dynamic proxy that routes the calls
    /// to the model.
    /// </summary>
    public abstract class QuestionAnswerViewModel : IQuestionAnswerViewModel
    {
        public event Action AnswerChosen = () => { }; 

        internal static IQuestionAnswerViewModel CreateQuestionAnswerViewModel(Answer answer)
        {
            return viewModelGenerator.Generate<QuestionAnswerViewModel>(answer);
        }

        private readonly Answer answer;
        private static readonly ViewModelGenerator viewModelGenerator = new ViewModelGenerator();
        private readonly Lazy<VoteAnswerUpCommand> voteUpProxy;
        private readonly Lazy<VoteAnswerDownCommand> voteDownProxy;
        private readonly Lazy<ChooseAnswerCommand> chooseAnswerProxy;

        protected QuestionAnswerViewModel(Answer answer)
        {
            using (var serviceClient = ServicesFactory.CreateClientOverflowServiceClient())
            {
                answer.Question = serviceClient.GetQuestion(answer);
            }

            voteUpProxy = new Lazy<VoteAnswerUpCommand>(() =>
                                                            {
                                                                var voteAnswerUpCommand = new VoteAnswerUpCommand(answer);
                                                                voteAnswerUpCommand.Executed += OnExecuted;
                                                                return voteAnswerUpCommand;
                                                            });
            voteDownProxy = new Lazy<VoteAnswerDownCommand>(() =>
                                                                {
                                                                    var voteAnswerDownCommand = new VoteAnswerDownCommand(answer);
                                                                    voteAnswerDownCommand.Executed += OnExecuted;
                                                                    return voteAnswerDownCommand;
                                                                });
            chooseAnswerProxy = new Lazy<ChooseAnswerCommand>(() =>
                                                                  {
                                                                      var chooseAnswerCommand = new ChooseAnswerCommand(answer);
                                                                      chooseAnswerCommand.Executed += OnExecuted;
                                                                      return chooseAnswerCommand;
                                                                  });
            this.answer = answer;
        }

        private void OnExecuted()
        {
            AnswerChosen();
        }

        public ICommand VoteUpCommand { get { return voteUpProxy.Value; } }
        public ICommand VoteDownCommand { get { return voteDownProxy.Value; } }

        public ICommand ChooseAnswerCommand { get { return chooseAnswerProxy.Value; } }

        public abstract string Content { get; }

        public bool IsCorrect
        {
            get { return answer.ID == answer.Question.CorrectAnswerID; }
        }

        public int Votes { get { return answer.UpVotes.Count - answer.DownVotes.Count; } }

    }
}